﻿/************************************************************************
 * SMLib - State Model Library
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     SMLib\Automata\Base\Sequence.cs
 * Description  :     Implementation of sequences of pair Symbols
 * Change log   :     -April 2013: First version
 * To Do        :
 ************************************************************************/
using System;
using System.Collections.Generic;

namespace SMLib.Automata.Base
{
    /// <summary>
    /// Implementation of a sequence (of pairSymbols)
    /// </summary>
    public class Sequence
    {
        List<PairOfSymbols> seq;

        /// <summary>
        /// Constructor
        /// </summary>
        public Sequence()
        {
            seq = new List<PairOfSymbols>();
        }

		/// <summary>
		/// Initializes a new instance of the <see cref="SMLib.Automata.Base.Sequence"/> class.
		/// </summary>
		/// <param name="sq">the sequence</param>
		public Sequence(Sequence sq)
		{
			seq = new List<PairOfSymbols>();
			for (int i=0; i<sq.Length; i++) {
				seq.Add (sq [i]);
			}
		}

		/// <summary>
		/// Parse the specified string as a sequence
		/// </summary>
		/// <param name='st'>
		/// The input string
		/// </param>
		public static Sequence Parse(string st){			
			if(st[0]!='[' || st[st.Length-1]!=']')
				throw new Exception("Bad format!");
			string st2=st.Substring(1,st.Length-2);
			string [] symbs= st2.Split(new char[]{'.'});
			Sequence sq=new Sequence();
			foreach(string symb in symbs)
			{
				string [] parts = symb.Split(new char[]{'/'});
				if(parts.Length!=2)
					throw new Exception("Bad format!");
				parts[0]=parts[0].Substring(1,parts[0].Length-1);
				parts[1]=parts[1].Substring(0,parts[1].Length-1);
				StringSymbol inp=new StringSymbol(parts[0]);
				//(parts[0]=="NULL"?null:new StringSymbol(parts[0]));
				StringSymbol otp=(parts[1]=="NULL"?null:new StringSymbol(parts[1]));
				PairOfSymbols p=new PairOfSymbols(inp,otp);
				sq.AddPair(p);
			}
			return sq;
		}
		
        /// <summary>
        /// Add one step of input-output to the sequence
        /// </summary>
        /// <param name="input">the input part of symbol</param>
        /// <param name="output">the output part of symbol</param>
        /// <returns>the current sequence with one more step</returns>
        public Sequence AddPair(ISymbol input, ISymbol output)
        {
            seq.Add(new PairOfSymbols(input, output));
            return this;
        }
		
		
        /// <summary>
        /// Convert the sequence to string
        /// </summary>
        /// <returns>the equivalent string</returns>
        public override string ToString()
        {
            string s = "[";
            for (int i = 0; i < seq.Count; i++)
                s += (seq[i].ToString() + (i == seq.Count - 1 ? "]" : "."));
            if (seq.Count == 0)
                s += "]";
            return s;
        }
		
		
        /// <summary>
        /// Add one step of input-output to the sequence
        /// </summary>
        /// <param name="io">the input-output pair</param>
        /// <returns>the current sequence with one more step</returns>
        public Sequence AddPair(PairOfSymbols io)
        {
            seq.Add(io);
            return this;
        }
		
		/// <summary>
		/// Removes the step at i.
		/// </summary>
		/// <returns>
		/// The <see cref="Sequence"/>.
		/// </returns>
		/// <param name='i'>
		/// index of the step to be removed
		/// </param>
		public Sequence RemovePairAt(int i)
		{
			seq.RemoveAt(i);
			return this;
		}
		
        /// <summary>
        /// Add steps into the sequence
        /// </summary>
        /// <param name="sts">the steps as pairs of symbols</param>
        /// <returns>the current sequence with some more steps</returns>
        public Sequence AddPairs(params PairOfSymbols[] sts)
        {
            seq.AddRange(sts);
            return this;
        }

        /// <summary>
        /// Add steps into the sequence
        /// </summary>
        /// <param name="sts">the steps as pairs of symbols</param>
        /// <returns>the current sequence with some more steps</returns>
        public Sequence AddPairs(params ISymbol[] sts)
        {
            if (sts.Length % 2 != 0)
            {
                throw new Exception("In Sequnece.AddSteps, you should provide an even number of symbols");
            }
            for (int i = 0; i < sts.Length; i += 2)
            {
                AddPair(sts[i], sts[i + 1]);
            }
            return this;
        }

        /// <summary>
        /// Calculate the input projection of a sequence
        /// </summary>
        /// <returns>the input project</returns>
        public Word InputProjection()
        {
            Word inpProj = new Word();
            for (int i = 0; i < Length; i++)
            {
                inpProj.AddSymbol(this[i].Input);
            }
            return inpProj;
        }

        /// <summary>
        /// calculate the output project of a sequence
        /// </summary>
        /// <returns>the output project</returns>
        public Word OutputProjection()
        {
            Word oupProj = new Word();
            for (int i = 0; i < Length; i++)
            {
                oupProj.AddSymbol(this[i].Output);
            }
            return oupProj;
        }

        /// <summary>
        /// A path containing the prefix of the path with length 'len'
        /// </summary>
        /// <param name="len">Length of prefix</param>
        /// <returns>the prefix sequence</returns>
        public Sequence Prefix(int len)
        {
            Sequence p = new Sequence();
            for (int i = 0; i < len; i++)
                p.AddPair(seq[i]);
            return p;
        }

        /// <summary>
        /// returns the pair symbol at the specific index of a sequence
        /// </summary>
        /// <param name="i">index</param>
        /// <returns>i-th pair of symbols in the sequence</returns>
        public PairOfSymbols this[int i]
        {
            get { return seq[i]; }
        }

		public List<PairOfSymbols> AllPairs()
		{
			return seq;
		}

        /// <summary>
        /// Length of this sequence (number of input/output pairs)
        /// </summary>
        public int Length
        {
            get
            {
                return seq.Count;
            }
        }
    }
}
